%include "boot.inc"
org 0x7e00
[bits 16]
mov ax,0xb800
mov gs,ax

;bootloader_tag:
mov ah,0x03  ;青色
mov ecx,bootloader_tag_end - bootloader_tag
xor ebx,ebx
add ebx,80*1*2 ;第二行
mov esi,bootloader_tag
output_bootloader_tag:
    mov al,[esi]
    mov word[gs:bx],ax
    inc esi
    add ebx,2
    loop output_bootloader_tag
    
;空描述符
mov dword[GDT_START_ADDRESS+0x00],0x00
mov dword[GDT_START_ADDRESS+0x04],0x00
;创建描述符，数据段，对应0-4GB的线性地址空间
mov dword[GDT_START_ADDRESS+0x08],0x0000ffff	;基地址为0，段界限为0xfffff
mov dword[GDT_START_ADDRESS+0x0c],0x00cf9200	;粒度为4kb，存储器段描述符
;建立保护模式下的堆栈段描述符
mov dword[GDT_START_ADDRESS+0x10],0x00000000	;基地址为0，段界限为0
mov dword[GDT_START_ADDRESS+0x14],0x00409600	;粒度为1个字节
;建立保护模式下的显存描述符
mov dword[GDT_START_ADDRESS+0x18],0x80007fff	;基地址为0xb8000，段界限0x07fff
mov dword[GDT_START_ADDRESS+0x1c],0x0040920b	;粒度为字节
;创建保护模式下的平坦模式代码段描述符
mov dword[GDT_START_ADDRESS+0x20],0x0000ffff	;基地址为0，段界限为0xfffff
mov dword[GDT_START_ADDRESS+0x24],0x00cf9800	;粒度为4kb，代码段描述符

;初始化描述符表寄存器GDTR
mov word[pgdt],39	;描述符表的界限
lgdt [pgdt]

;打开第21根地址线
in al,0x92		;南桥芯片内的端口
or al,0000_0010B	
out 0x92,al		;打开A20
;设置cr0保护模式开关位
cli			;中断机制尚未工作，禁用中断
mov eax,cr0
or eax,1
mov cr0,eax		;设置PE位
;远跳转进入保护模式
jmp dword CODE_SELECTOR:protect_mode_begin

;16位的描述符选择子：32位偏移
;清流水线，串行化处理器
[bits 32]
protect_mode_begin:
mov eax,DATA_SELECTOR	;加载数据段选择子
mov ds,eax
mov es,eax
mov eax,STACK_SELECTOR
mov ss,eax
mov eax,VIDEO_SELECTOR
mov gs,eax

mov ecx,protect_mode_tag_end - protect_mode_tag
mov ebx,80*2*2		;第三行显示
mov esi,protect_mode_tag
mov ah,0x3
output_protect_mode_tag:
    mov al,[esi]
    mov word[gs:ebx],ax
    add ebx,2
    inc esi
    loop output_protect_mode_tag

mov eax,KERNEL_START_SECTOR
mov ebx,KERNEL_START_ADDRESS
mov ecx,KERNEL_SECTOR_COUNT
load_kernel:
    push eax
    push ebx
    call asm_read_hard_disk	;读取硬盘
    add esp,8
    inc eax
    add ebx,512
    loop load_kernel
jmp dword CODE_SELECTOR:KERNEL_START_ADDRESS	;跳转到kernel

; asm_read_hard_disk(memory,block)
;加载逻辑扇区号为block的扇区到内存地址memory
asm_read_hard_disk:
    push ebp
    mov ebp,esp
    push eax
    push ebx
    push ecx
    push edx
    
    mov eax,[ebp+4*3]	;逻辑扇区低16位
    
    mov edx,0x1f3	;0x1f3
    out dx,al		;lba地址7~0
   
    inc edx		; 0x1f4
    mov al,ah
    out dx,al		;lba地址15~8
    
    xor eax,eax
    inc edx		;0x1f5
    out dx,al		;lba地址23~16=0
    
    inc edx		;0x1f6
    mov al,ah
    and al,0x0f
    or al,0xe0
    out dx,al		;lba地址27~24=0
    
    mov edx,0x1f2	;0x1f2
    mov al,1
    out dx,al		;读取1个扇区
    
    mov edx,0x1f7	;0x1f7
    mov al,0x20		;读命令
    out dx,al
    
    ;等待其他操作
    .waits:
        in al,dx	;dx=0x1f7
        and al,0x88
        cmp al,0x08
        jnz .waits
        
    ;读取512字节到地址ds:bx
    mov ebx,[ebp+4*2]
    mov ecx,256		;每次读取一个字，2个字节，因此读取256次
    mov edx,0x1f0	;0x1f0
    .readw:
        in ax,dx
        mov [ebx],eax
        add ebx,2
        loop .readw
    
    pop edx
    pop ecx
    pop ebx
    pop eax
    pop ebp
    ret

.data:
pgdt dw 0
        dd GDT_START_ADDRESS
bootloader_tag db 'run bootloader...'
bootloader_tag_end:
protect_mode_tag db 'You enter protect mode!'
protect_mode_tag_end:
